home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / inetd / inetd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-17  |  21.7 KB  |  997 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #ifndef lint
  14. char copyright[] =
  15. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  16.  All rights reserved.\n";
  17. #endif not lint
  18.  
  19. #ifndef lint
  20. static char sccsid[] = "@(#)inetd.c    5.7 (Berkeley) 8/19/86";
  21. #endif not lint
  22.  
  23. /*
  24.  * Inetd - Internet super-server
  25.  *
  26.  * This program invokes all internet services as needed.
  27.  * connection-oriented services are invoked each time a
  28.  * connection is made, by creating a process.  This process
  29.  * is passed the connection as file descriptor 0 and is
  30.  * expected to do a getpeername to find out the source host
  31.  * and port.
  32.  *
  33.  * Datagram oriented services are invoked when a datagram
  34.  * arrives; a process is created and passed a pending message
  35.  * on file descriptor 0.  Datagram servers may either connect
  36.  * to their peer, freeing up the original socket for inetd
  37.  * to receive further messages on, or ``take over the socket'',
  38.  * processing all arriving datagrams and, eventually, timing
  39.  * out.     The first type of server is said to be ``multi-threaded'';
  40.  * the second type of server ``single-threaded''. 
  41.  *
  42.  * Inetd uses a configuration file which is read at startup
  43.  * and, possibly, at some later time in response to a hangup signal.
  44.  * The configuration file is ``free format'' with fields given in the
  45.  * order shown below.  Continuation lines for an entry must being with
  46.  * a space or tab.  All fields must be present in each entry.
  47.  *
  48.  *    service name            must be in /etc/services
  49.  *    socket type            stream/dgram/raw/rdm/seqpacket
  50.  *    protocol            must be in /etc/protocols
  51.  *    wait/nowait            single-threaded/multi-threaded
  52.  *    user                user to run daemon as
  53.  *    server program            full path name
  54.  *    server program arguments    maximum of MAXARGS (5)
  55.  *
  56.  * Comment lines are indicated by a `#' in column 1.
  57.  */
  58. #include <sys/param.h>
  59. #include <sys/stat.h>
  60. #include <sys/socket.h>
  61. #include <sys/file.h>
  62. #include <sys/wait.h>
  63. #include <sys/time.h>
  64. #include <sys/resource.h>
  65.  
  66. #include <netinet/in.h>
  67. #include <arpa/inet.h>
  68.  
  69. #include <errno.h>
  70. #include <stdio.h>
  71. #include <signal.h>
  72. #include <netdb.h>
  73. #include <syslog.h>
  74. #include <pwd.h>
  75.  
  76.  
  77. #define    TOOMANY        40        /* don't start more than TOOMANY */
  78. #define    CNT_INTVL    60        /* servers in CNT_INTVL sec. */
  79. #define    RETRYTIME    (60*10)        /* retry after bind or server fail */
  80.  
  81. #define    SIGBLOCK    (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
  82.  
  83. extern    int errno;
  84.  
  85. void    reapchild(), retry(), config();
  86. char    *index();
  87. char    *malloc();
  88.  
  89. int    debug = 0;
  90. int    nsock, maxsock;
  91. fd_set    allsock;
  92. int    options;
  93. int    timingout;
  94. struct    servent *sp;
  95.  
  96. struct    servtab {
  97.     char    *se_service;        /* name of service */
  98.     int    se_socktype;        /* type of socket to use */
  99.     char    *se_proto;        /* protocol used */
  100.     int      se_wait;        /* single threaded server */
  101.     int      se_checked;        /* looked at during merge */
  102.     char    *se_user;        /* user name to run as */
  103.     struct    biltin *se_bi;        /* if built-in, description */
  104.     char    *se_server;        /* server program */
  105. #define MAXARGV 5
  106.     char    *se_argv[MAXARGV+1];    /* program arguments */
  107.     int    se_fd;            /* open descriptor */
  108.     struct    sockaddr_in se_ctrladdr;/* bound address */
  109.     int    se_count;        /* number started since se_time */
  110.     struct    timeval se_time;    /* start of se_count */
  111.     struct    servtab *se_next;
  112. } *servtab;
  113.  
  114. int echo_stream(), discard_stream(), machtime_stream();
  115. int daytime_stream(), chargen_stream();
  116. int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
  117.  
  118. struct biltin {
  119.     char    *bi_service;        /* internally provided service name */
  120.     int    bi_socktype;        /* type of socket supported */
  121.     int      bi_fork;        /* 1 if should fork before call */
  122.     int      bi_wait;        /* 1 if should wait for child */
  123.     int    (*bi_fn)();        /* function which performs it */
  124. } biltins[] = {
  125.     /* Echo received data */
  126.     "echo",        SOCK_STREAM,    1, 0,    echo_stream,
  127.     "echo",        SOCK_DGRAM,    0, 0,    echo_dg,
  128.  
  129.     /* Internet /dev/null */
  130.     "discard",    SOCK_STREAM,    1, 0,    discard_stream,
  131.     "discard",    SOCK_DGRAM,    0, 0,    discard_dg,
  132.  
  133.     /* Return 32 bit time since 1970 */
  134.     "time",        SOCK_STREAM,    0, 0,    machtime_stream,
  135.     "time",        SOCK_DGRAM,    0, 0,    machtime_dg,
  136.  
  137.     /* Return human-readable time */
  138.     "daytime",    SOCK_STREAM,    0, 0,    daytime_stream,
  139.     "daytime",    SOCK_DGRAM,    0, 0,    daytime_dg,
  140.  
  141.     /* Familiar character generator */
  142.     "chargen",    SOCK_STREAM,    1, 0,    chargen_stream,
  143.     "chargen",    SOCK_DGRAM,    0, 0,    chargen_dg,
  144.     0
  145. };
  146.  
  147. #define NUMINT    (sizeof(intab) / sizeof(struct inent))
  148. char    *CONFIG = "/sprite/daemons/inetd.conf";
  149. char    **Argv;
  150. char     *LastArg;
  151.  
  152. main(argc, argv, envp)
  153.     int argc;
  154.     char *argv[], *envp[];
  155. {
  156.     register struct servtab *sep;
  157.     register struct passwd *pwd;
  158.     char *cp, buf[50];
  159.     int pid, i, dofork;
  160.     struct sigvec sv;
  161.     int       selectErrors = 0;
  162.     char *childEnv[4];
  163.     char **childEnvPtr = childEnv;
  164.     char **envPtr;
  165.     extern char **environ;
  166.  
  167.  
  168.     /*
  169.      * Get the "true" environment and pull out the variables
  170.      * we want to pass to our children.
  171.      */
  172.     for (envPtr = environ; *envPtr != NULL; envPtr++) {
  173.         if (!strncmp(*envPtr, "MACHINE=", strlen("MACHINE=")) ||
  174.         !strncmp(*envPtr, "SPRITE_OS=", strlen("SPRITE_OS=")) ||
  175.         !strncmp(*envPtr, "HOME=", strlen("HOME="))) {
  176.         *childEnvPtr = *envPtr;
  177.         childEnvPtr++;
  178.         }
  179.     }
  180.  
  181.     *childEnvPtr = NULL;
  182.  
  183.     /*
  184.      * Make sure our real uid is root.  This also makes sure we were
  185.      * at least invoked with an effective uid of root.
  186.      */
  187.     if (setreuid(0, 0) < 0) {
  188.         perror("setreuid");
  189.     }
  190.     
  191.     Argv = argv;
  192.     if (envp == 0 || *envp == 0)
  193.         envp = argv;
  194.     while (*envp)
  195.         envp++;
  196.     LastArg = envp[-1] + strlen(envp[-1]);
  197.     argc--, argv++;
  198.     while (argc > 0 && *argv[0] == '-') {
  199.         for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
  200.  
  201.         case 'd':
  202.             debug = 1;
  203.             options |= SO_DEBUG;
  204.             break;
  205.  
  206.         default:
  207.             fprintf(stderr,
  208.                 "inetd: Unknown flag -%c ignored.\n", *cp);
  209.             break;
  210.         }
  211. nextopt:
  212.         argc--, argv++;
  213.     }
  214.     if (argc > 0)
  215.         CONFIG = argv[0];
  216.     if (!debug) {
  217.         if (fork())
  218.             exit(0);
  219.         { int s;
  220.         for (s = 0; s < 10; s++)
  221.             (void) close(s);
  222.         }
  223.         (void) open("/", O_RDONLY);
  224.         (void) dup2(0, 1);
  225.         (void) dup2(0, 2);
  226.     }
  227.     openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
  228.     bzero((char *)&sv, sizeof(sv));
  229.     sv.sv_mask = SIGBLOCK;
  230.     sv.sv_handler = retry;
  231.     sigvec(SIGALRM, &sv, (struct sigvec *)0);
  232.     config();
  233.     sv.sv_handler = config;
  234.     sigvec(SIGHUP, &sv, (struct sigvec *)0);
  235.     sv.sv_handler = reapchild;
  236.     sigvec(SIGCHLD, &sv, (struct sigvec *)0);
  237.  
  238.  
  239.     for (;;) {
  240.         int s, ctrl, n, errorCount;
  241.         fd_set readable;
  242.  
  243.         while (nsock == 0)
  244.             sigpause(0);
  245.         readable = allsock;
  246.         if ((n = select(maxsock + 1, &readable, (fd_set *)0,
  247.         (fd_set *)0, (struct timeval *)0)) <= 0) {
  248.             if (n < 0 && errno != EINTR) {
  249.             syslog(LOG_WARNING, "select: %m (num=%d, read=%x)\n",
  250.                 maxsock+1, readable);
  251.             selectErrors++;
  252.             if (selectErrors > 25) {
  253.                 syslog(LOG_ERR,
  254.                     "Exiting: Too many select errors\n");
  255.                 exit(1);
  256.             }
  257.             }
  258.             sleep(1);
  259.             continue;
  260.         }
  261.         errorCount = n;
  262.         for (sep = servtab; n && sep; sep = sep->se_next)
  263.         if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
  264.         n--;
  265.         if (debug)
  266.             fprintf(stderr, "someone wants %s\n", sep->se_service);
  267.         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
  268.             ctrl = accept(sep->se_fd, (struct sockaddr *)0,
  269.                 (int *)0);
  270.             if (debug)
  271.                 fprintf(stderr, "accept, ctrl %d\n", ctrl);
  272.             if (ctrl < 0) {
  273.                 if (errno == EINTR)
  274.                     continue;
  275.                 syslog(LOG_WARNING, "%s/%s accept: %m",
  276.                         sep->se_service, sep->se_proto);
  277.                 FD_CLR(sep->se_fd, &allsock);
  278.                 nsock--;
  279.                 (void) close(sep->se_fd);
  280.                 sep->se_fd = -1;
  281.                 continue;
  282.             }
  283.         } else
  284.             ctrl = sep->se_fd;
  285.         (void) sigblock(SIGBLOCK);
  286.         pid = 0;
  287.         dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
  288.         if (dofork) {
  289.             if (debug) 
  290.                 fprintf(stderr, "doing fork\n");
  291.             if (sep->se_count++ == 0)
  292.                 (void)gettimeofday(&sep->se_time,
  293.                     (struct timezone *)0);
  294.             else if (sep->se_count >= TOOMANY) {
  295.                 struct timeval now;
  296.  
  297.                 (void)gettimeofday(&now, (struct timezone *)0);
  298.                 if (now.tv_sec - sep->se_time.tv_sec >
  299.                     CNT_INTVL) {
  300.                     sep->se_time = now;
  301.                     sep->se_count = 1;
  302.                 } else {
  303.                     syslog(LOG_ERR,
  304.             "%s/%s server failing (looping), service terminated\n",
  305.                         sep->se_service, sep->se_proto);
  306.                     FD_CLR(sep->se_fd, &allsock);
  307.                     (void) close(sep->se_fd);
  308.                     sep->se_fd = -1;
  309.                     sep->se_count = 0;
  310.                     nsock--;
  311.                     sigsetmask(0);
  312.                     if (!timingout) {
  313.                         timingout = 1;
  314.                         alarm(RETRYTIME);
  315.                     }
  316.                     continue;
  317.                 }
  318.             }
  319.             pid = fork();
  320.         }
  321.         if (pid < 0) {
  322.             if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
  323.                 close(ctrl);
  324.             sigsetmask(0);
  325.             sleep(1);
  326.             continue;
  327.         }
  328.         if (pid && sep->se_wait) {
  329.             sep->se_wait = pid;
  330.             FD_CLR(sep->se_fd, &allsock);
  331.             nsock--;
  332.         }
  333.         sigsetmask(0);
  334.         if (pid == 0) {
  335.             if (dofork)
  336.                 for (i = getdtablesize(); --i > 2; )
  337.                     if (i != ctrl)
  338.                         close(i);
  339.             if (sep->se_bi)
  340.                 (*sep->se_bi->bi_fn)(ctrl, sep);
  341.             else {
  342.                 dup2(ctrl, 0);
  343.                 close(ctrl);
  344.                 dup2(0, 1);
  345.                 dup2(0, 2);
  346.                 if ((pwd = getpwnam(sep->se_user)) == NULL) {
  347.                     syslog(LOG_ERR,
  348.                         "getpwnam: %s: No such user",
  349.                         sep->se_user);
  350.                     if (sep->se_socktype != SOCK_STREAM)
  351.                         recv(0, buf, sizeof (buf), 0);
  352.                     _exit(1);
  353.                 }
  354.                 if (pwd->pw_uid) {
  355.                     (void) setgid((gid_t)pwd->pw_gid);
  356.                     initgroups(pwd->pw_name, pwd->pw_gid);
  357.                     (void) setuid((uid_t)pwd->pw_uid);
  358.                 }
  359.                 if (debug)
  360.                     syslog(LOG_INFO, "execl %s",
  361.                         sep->se_server);
  362.                 execve(sep->se_server, sep->se_argv, childEnv);
  363.                 if (sep->se_socktype != SOCK_STREAM)
  364.                     recv(0, buf, sizeof (buf), 0);
  365.                 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
  366.                 _exit(1);
  367.             }
  368.         }
  369.         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
  370.             close(ctrl);
  371.         }
  372.     }
  373. }
  374.  
  375. void
  376. reapchild()
  377. {
  378.     union wait status;
  379.     int pid;
  380.     register struct servtab *sep;
  381.  
  382.     if (debug)
  383.         fprintf(stderr, "entering reapchild()\n");
  384.     for (;;) {
  385.         pid = wait3(&status, WNOHANG, (struct rusage *)0);
  386.         if (pid <= 0)
  387.             break;
  388.         if (debug)
  389.             fprintf(stderr, "%d reaped\n", pid);
  390.         for (sep = servtab; sep; sep = sep->se_next)
  391.             if (sep->se_wait == pid) {
  392.                 if (status.w_status)
  393.                     syslog(LOG_WARNING,
  394.                         "%s: exit status 0x%x",
  395.                         sep->se_server, status);
  396.                 if (debug)
  397.                     fprintf(stderr, "restored %s, fd %d\n",
  398.                         sep->se_service, sep->se_fd);
  399.                 FD_SET(sep->se_fd, &allsock);
  400.                 nsock++;
  401.                 sep->se_wait = 1;
  402.             }
  403.     }
  404.     if (debug)
  405.         fprintf(stderr, "leaving reapchild()\n");
  406. }
  407.  
  408. void
  409. config()
  410. {
  411.     register struct servtab *sep, *cp, **sepp;
  412.     struct servtab *getconfigent(), *enter();
  413.     int omask;
  414.  
  415.     if (!setconfig()) {
  416.         syslog(LOG_ERR, "%s: %m", CONFIG);
  417.         return;
  418.     }
  419.     for (sep = servtab; sep; sep = sep->se_next)
  420.         sep->se_checked = 0;
  421.     while (cp = getconfigent()) {
  422.         for (sep = servtab; sep; sep = sep->se_next)
  423.             if (strcmp(sep->se_service, cp->se_service) == 0 &&
  424.                 strcmp(sep->se_proto, cp->se_proto) == 0)
  425.                 break;
  426.         if (sep != 0) {
  427.             int i;
  428.  
  429.             omask = sigblock(SIGBLOCK);
  430.             if (cp->se_bi == 0)
  431.                 sep->se_wait = cp->se_wait;
  432. #define SWAP(a, b) { char *c = a; a = b; b = c; }
  433.             if (cp->se_user)
  434.                 SWAP(sep->se_user, cp->se_user);
  435.             if (cp->se_server)
  436.                 SWAP(sep->se_server, cp->se_server);
  437.             for (i = 0; i < MAXARGV; i++)
  438.                 SWAP(sep->se_argv[i], cp->se_argv[i]);
  439.             sigsetmask(omask);
  440.             freeconfig(cp);
  441.             if (debug)
  442.                 print_service("REDO", sep);
  443.         } else {
  444.             sep = enter(cp);
  445.             if (debug)
  446.                 print_service("ADD ", sep);
  447.         }
  448.         sep->se_checked = 1;
  449.         sp = getservbyname(sep->se_service, sep->se_proto);
  450.         if (sp == 0) {
  451.             syslog(LOG_ERR, "%s/%s: unknown service",
  452.                 sep->se_service, sep->se_proto);
  453.             continue;
  454.         }
  455.         if (sp->s_port != sep->se_ctrladdr.sin_port) {
  456.             sep->se_ctrladdr.sin_port = sp->s_port;
  457.             if (sep->se_fd != -1)
  458.                 (void) close(sep->se_fd);
  459.             sep->se_fd = -1;
  460.         }
  461.         if (sep->se_fd == -1)
  462.             setup(sep);
  463.     }
  464.     endconfig();
  465.     /*
  466.      * Purge anything not looked at above.
  467.      */
  468.     omask = sigblock(SIGBLOCK);
  469.     sepp = &servtab;
  470.     while (sep = *sepp) {
  471.         if (sep->se_checked) {
  472.             sepp = &sep->se_next;
  473.             continue;
  474.         }
  475.         *sepp = sep->se_next;
  476.         if (sep->se_fd != -1) {
  477.             FD_CLR(sep->se_fd, &allsock);
  478.             nsock--;
  479.             (void) close(sep->se_fd);
  480.         }
  481.         if (debug)
  482.             print_service("FREE", sep);
  483.         freeconfig(sep);
  484.         free((char *)sep);
  485.     }
  486.     (void) sigsetmask(omask);
  487. }
  488.  
  489. void
  490. retry()
  491. {
  492.     register struct servtab *sep;
  493.  
  494.     timingout = 0;
  495.     for (sep = servtab; sep; sep = sep->se_next)
  496.         if (sep->se_fd == -1)
  497.             setup(sep);
  498. }
  499.  
  500. setup(sep)
  501.     register struct servtab *sep;
  502. {
  503.     int on = 1;
  504.  
  505.     if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
  506.         syslog(LOG_ERR, "%s/%s: socket: %m",
  507.             sep->se_service, sep->se_proto);
  508.         return;
  509.     }
  510. #define    turnon(fd, opt) \
  511. setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
  512.     if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
  513.         turnon(sep->se_fd, SO_DEBUG) < 0)
  514.         syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
  515.     if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
  516.         syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
  517. #undef turnon
  518.     if (bind(sep->se_fd, &sep->se_ctrladdr,
  519.         sizeof (sep->se_ctrladdr)) < 0) {
  520.         syslog(LOG_ERR, "%s/%s: bind: %m",
  521.             sep->se_service, sep->se_proto);
  522.         (void) close(sep->se_fd);
  523.         sep->se_fd = -1;
  524.         if (!timingout) {
  525.             timingout = 1;
  526.             alarm(RETRYTIME);
  527.         }
  528.         return;
  529.     }
  530.     if (sep->se_socktype == SOCK_STREAM)
  531.         listen(sep->se_fd, 10);
  532.     FD_SET(sep->se_fd, &allsock);
  533.     nsock++;
  534.     if (sep->se_fd > maxsock)
  535.         maxsock = sep->se_fd;
  536. }
  537.  
  538. struct servtab *
  539. enter(cp)
  540.     struct servtab *cp;
  541. {
  542.     register struct servtab *sep;
  543.     int omask;
  544.     char *strdup();
  545.  
  546.     sep = (struct servtab *)malloc(sizeof (*sep));
  547.     if (sep == (struct servtab *)0) {
  548.         syslog(LOG_ERR, "Out of memory.");
  549.         exit(-1);
  550.     }
  551.     *sep = *cp;
  552.     sep->se_fd = -1;
  553.     omask = sigblock(SIGBLOCK);
  554.     sep->se_next = servtab;
  555.     servtab = sep;
  556.     sigsetmask(omask);
  557.     return (sep);
  558. }
  559.  
  560. FILE    *fconfig = NULL;
  561. struct    servtab serv;
  562. char    line[256];
  563. char    *skip(), *nextline();
  564.  
  565. setconfig()
  566. {
  567.  
  568.     if (fconfig != NULL) {
  569.         fseek(fconfig, 0L, L_SET);
  570.         return (1);
  571.     }
  572.     fconfig = fopen(CONFIG, "r");
  573.     return (fconfig != NULL);
  574. }
  575.  
  576. endconfig()
  577. {
  578.  
  579.     if (fconfig == NULL)
  580.         return;
  581.     fclose(fconfig);
  582.     fconfig = NULL;
  583. }
  584.  
  585. struct servtab *
  586. getconfigent()
  587. {
  588.     register struct servtab *sep = &serv;
  589.     char *cp, *arg;
  590.     int argc;
  591.     char    *strdup();
  592.  
  593. more:
  594.     while ((cp = nextline(fconfig)) && *cp == '#')
  595.         ;
  596.     if (cp == NULL)
  597.         return ((struct servtab *)0);
  598.     sep->se_service = strdup(skip(&cp));
  599.     arg = skip(&cp);
  600.     if (strcmp(arg, "stream") == 0)
  601.         sep->se_socktype = SOCK_STREAM;
  602.     else if (strcmp(arg, "dgram") == 0)
  603.         sep->se_socktype = SOCK_DGRAM;
  604.     else if (strcmp(arg, "rdm") == 0)
  605.         sep->se_socktype = SOCK_RDM;
  606.     else if (strcmp(arg, "seqpacket") == 0)
  607.         sep->se_socktype = SOCK_SEQPACKET;
  608.     else if (strcmp(arg, "raw") == 0)
  609.         sep->se_socktype = SOCK_RAW;
  610.     else
  611.         sep->se_socktype = -1;
  612.     sep->se_proto = strdup(skip(&cp));
  613.     arg = skip(&cp);
  614.     sep->se_wait = strcmp(arg, "wait") == 0;
  615.     sep->se_user = strdup(skip(&cp));
  616.     sep->se_server = strdup(skip(&cp));
  617.     if (strcmp(sep->se_server, "internal") == 0) {
  618.         register struct biltin *bi;
  619.  
  620.         for (bi = biltins; bi->bi_service; bi++)
  621.             if (bi->bi_socktype == sep->se_socktype &&
  622.                 strcmp(bi->bi_service, sep->se_service) == 0)
  623.                 break;
  624.         if (bi->bi_service == 0) {
  625.             syslog(LOG_ERR, "internal service %s unknown\n",
  626.                 sep->se_service);
  627.             goto more;
  628.         }
  629.         sep->se_bi = bi;
  630.         sep->se_wait = bi->bi_wait;
  631.     } else
  632.         sep->se_bi = NULL;
  633.     argc = 0;
  634.     for (arg = skip(&cp); cp; arg = skip(&cp))
  635.         if (argc < MAXARGV)
  636.             sep->se_argv[argc++] = strdup(arg);
  637.     while (argc <= MAXARGV)
  638.         sep->se_argv[argc++] = NULL;
  639.     return (sep);
  640. }
  641.  
  642. freeconfig(cp)
  643.     register struct servtab *cp;
  644. {
  645.     int i;
  646.  
  647.     if (cp->se_service)
  648.         free(cp->se_service);
  649.     if (cp->se_proto)
  650.         free(cp->se_proto);
  651.     if (cp->se_user)
  652.         free(cp->se_user);
  653.     if (cp->se_server)
  654.         free(cp->se_server);
  655.     for (i = 0; i < MAXARGV; i++)
  656.         if (cp->se_argv[i])
  657.             free(cp->se_argv[i]);
  658. }
  659.  
  660. char *
  661. skip(cpp)
  662.     char **cpp;
  663. {
  664.     register char *cp = *cpp;
  665.     char *start;
  666.  
  667. again:
  668.     while (*cp == ' ' || *cp == '\t')
  669.         cp++;
  670.     if (*cp == '\0') {
  671.         char c;
  672.  
  673.         c = getc(fconfig);
  674.         ungetc(c, fconfig);
  675.         if (c == ' ' || c == '\t')
  676.             if (cp = nextline(fconfig))
  677.                 goto again;
  678.         *cpp = (char *)0;
  679.         return ((char *)0);
  680.     }
  681.     start = cp;
  682.     while (*cp && *cp != ' ' && *cp != '\t')
  683.         cp++;
  684.     if (*cp != '\0')
  685.         *cp++ = '\0';
  686.     *cpp = cp;
  687.     return (start);
  688. }
  689.  
  690. char *
  691. nextline(fd)
  692.     FILE *fd;
  693. {
  694.     char *cp;
  695.  
  696.     if (fgets(line, sizeof (line), fd) == NULL)
  697.         return ((char *)0);
  698.     cp = index(line, '\n');
  699.     if (cp)
  700.         *cp = '\0';
  701.     return (line);
  702. }
  703.  
  704. char *
  705. strdup(cp)
  706.     char *cp;
  707. {
  708.     char *new;
  709.  
  710.     if (cp == NULL)
  711.         cp = "";
  712.     new = malloc((unsigned)(strlen(cp) + 1));
  713.     if (new == (char *)0) {
  714.         syslog(LOG_ERR, "Out of memory.");
  715.         exit(-1);
  716.     }
  717.     strcpy(new, cp);
  718.     return (new);
  719. }
  720.  
  721. setproctitle(a, s)
  722.     char *a;
  723.     int s;
  724. {
  725.     int size;
  726.     register char *cp;
  727.     struct sockaddr_in sin;
  728.     char buf[80];
  729.  
  730.     cp = Argv[0];
  731.     size = sizeof(sin);
  732.     if (getpeername(s, &sin, &size) == 0)
  733.         sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 
  734.     else
  735.         sprintf(buf, "-%s", a); 
  736.     strncpy(cp, buf, LastArg - cp);
  737.     cp += strlen(cp);
  738.     while (cp < LastArg)
  739.         *cp++ = ' ';
  740. }
  741.  
  742. /*
  743.  * Internet services provided internally by inetd:
  744.  */
  745.  
  746. /* ARGSUSED */
  747. echo_stream(s, sep)        /* Echo service -- echo data back */
  748.     int s;
  749.     struct servtab *sep;
  750. {
  751.     char buffer[BUFSIZ];
  752.     int i;
  753.  
  754.     setproctitle("echo", s);
  755.     while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
  756.         write(s, buffer, i) > 0)
  757.         ;
  758.     exit(0);
  759. }
  760.  
  761. /* ARGSUSED */
  762. echo_dg(s, sep)            /* Echo service -- echo data back */
  763.     int s;
  764.     struct servtab *sep;
  765. {
  766.     char buffer[BUFSIZ];
  767.     int i, size;
  768.     struct sockaddr sa;
  769.  
  770.     size = sizeof(sa);
  771.     if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) {
  772.         close(s);
  773.         return;
  774.     }
  775.     (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
  776. }
  777.  
  778. /* ARGSUSED */
  779. discard_stream(s, sep)        /* Discard service -- ignore data */
  780.     int s;
  781.     struct servtab *sep;
  782. {
  783.     char buffer[BUFSIZ];
  784.  
  785.     setproctitle("discard", s);
  786.     while (1) {
  787.         while (read(s, buffer, sizeof(buffer)) > 0)
  788.             ;
  789.         if (errno != EINTR)
  790.             break;
  791.     }
  792.     exit(0);
  793. }
  794.  
  795. /* ARGSUSED */
  796. discard_dg(s, sep)        /* Discard service -- ignore data */
  797.     int s;
  798.     struct servtab *sep;
  799. {
  800.     char buffer[BUFSIZ];
  801.  
  802.     (void) read(s, buffer, sizeof(buffer));
  803. }
  804.  
  805. #include <ctype.h>
  806. #define LINESIZ 72
  807. char ring[128];
  808. char *endring;
  809.  
  810. initring()
  811. {
  812.     register int i;
  813.  
  814.     endring = ring;
  815.  
  816.     for (i = 0; i <= 128; ++i)
  817.         if (isprint(i))
  818.             *endring++ = i;
  819. }
  820.  
  821. /* ARGSUSED */
  822. chargen_stream(s, sep)        /* Character generator */
  823.     int s;
  824.     struct servtab *sep;
  825. {
  826.     char text[LINESIZ+2];
  827.     register int i;
  828.     register char *rp, *rs, *dp;
  829.  
  830.     setproctitle("discard", s);
  831.     if (endring == 0)
  832.         initring();
  833.  
  834.     for (rs = ring; ; ++rs) {
  835.         if (rs >= endring)
  836.             rs = ring;
  837.         rp = rs;
  838.         dp = text;
  839.         i = MIN(LINESIZ, endring - rp);
  840.         bcopy(rp, dp, i);
  841.         dp += i;
  842.         if ((rp += i) >= endring)
  843.             rp = ring;
  844.         if (i < LINESIZ) {
  845.             i = LINESIZ - i;
  846.             bcopy(rp, dp, i);
  847.             dp += i;
  848.             if ((rp += i) >= endring)
  849.                 rp = ring;
  850.         }
  851.         *dp++ = '\r';
  852.         *dp++ = '\n';
  853.  
  854.         if (write(s, text, dp - text) != dp - text)
  855.             break;
  856.     }
  857.     exit(0);
  858. }
  859.  
  860. /* ARGSUSED */
  861. chargen_dg(s, sep)        /* Character generator */
  862.     int s;
  863.     struct servtab *sep;
  864. {
  865.     char text[LINESIZ+2];
  866.     register int i;
  867.     register char *rp;
  868.     static char *rs = ring;
  869.     struct sockaddr sa;
  870.     int size;
  871.  
  872.     if (endring == 0)
  873.         initring();
  874.  
  875.     size = sizeof(sa);
  876.     if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) {
  877.         close(s);
  878.         return;
  879.     }
  880.     rp = rs;
  881.     if (rs++ >= endring)
  882.         rs = ring;
  883.     i = MIN(LINESIZ - 2, endring - rp);
  884.     bcopy(rp, text, i);
  885.     if ((rp += i) >= endring)
  886.         rp = ring;
  887.     if (i < LINESIZ - 2) {
  888.         bcopy(rp, text, i);
  889.         if ((rp += i) >= endring)
  890.             rp = ring;
  891.     }
  892.     text[LINESIZ - 2] = '\r';
  893.     text[LINESIZ - 1] = '\n';
  894.  
  895.     (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
  896. }
  897.  
  898. /*
  899.  * Return a machine readable date and time, in the form of the
  900.  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
  901.  * returns the number of seconds since midnight, Jan 1, 1970,
  902.  * we must add 2208988800 seconds to this figure to make up for
  903.  * some seventy years Bell Labs was asleep.
  904.  */
  905.  
  906. long
  907. machtime()
  908. {
  909.     struct timeval tv;
  910.  
  911.     if (gettimeofday(&tv, (struct timezone *)0) < 0) {
  912.         fprintf(stderr, "Unable to get time of day\n");
  913.         return (0L);
  914.     }
  915.     return (htonl((long)tv.tv_sec + 2208988800));
  916. }
  917.  
  918. /* ARGSUSED */
  919. machtime_stream(s, sep)
  920.     int s;
  921.     struct servtab *sep;
  922. {
  923.     long result;
  924.  
  925.     result = machtime();
  926.     (void) write(s, (char *) &result, sizeof(result));
  927. }
  928.  
  929. /* ARGSUSED */
  930. machtime_dg(s, sep)
  931.     int s;
  932.     struct servtab *sep;
  933. {
  934.     long result;
  935.     struct sockaddr sa;
  936.     int size;
  937.  
  938.     size = sizeof(sa);
  939.     if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) {
  940.         close(s);
  941.         return;
  942.     }
  943.     result = machtime();
  944.     (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
  945. }
  946.  
  947. /* ARGSUSED */
  948. daytime_stream(s, sep)        /* Return human-readable time of day */
  949.     int s;
  950.     struct servtab *sep;
  951. {
  952.     char buffer[256];
  953.     time_t time(), clock;
  954.     char *ctime();
  955.  
  956.     clock = time((time_t *) 0);
  957.  
  958.     sprintf(buffer, "%s\r", ctime(&clock));
  959.     (void) write(s, buffer, strlen(buffer));
  960. }
  961.  
  962. /* ARGSUSED */
  963. daytime_dg(s, sep)        /* Return human-readable time of day */
  964.     int s;
  965.     struct servtab *sep;
  966. {
  967.     char buffer[256];
  968.     time_t time(), clock;
  969.     struct sockaddr sa;
  970.     int size;
  971.     char *ctime();
  972.  
  973.     clock = time((time_t *) 0);
  974.  
  975.     size = sizeof(sa);
  976.     if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) {
  977.         close(s);
  978.         return;
  979.     }
  980.     sprintf(buffer, "%s\r", ctime(&clock));
  981.     (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
  982. }
  983.  
  984. /*
  985.  * print_service:
  986.  *    Dump relevant information to stderr
  987.  */
  988. print_service(action, sep)
  989.     char *action;
  990.     struct servtab *sep;
  991. {
  992.     fprintf(stderr,
  993.         "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
  994.         action, sep->se_service, sep->se_proto,
  995.         sep->se_wait, sep->se_user, sep->se_bi, sep->se_server);
  996. }
  997.